#!/bin/bash
#
# Copyright (C) 2014 Wenva <lvyexuwenfa100@126.com>
# 
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is furnished
# to do so, subject to the following conditions:
# 
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
# 
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

set -e

AUTHOR="smallmuou<smallmuou@163.com>"
VERSION=1.0.0

spushd() {
     pushd "$1" 2>&1> /dev/null
}

spopd() {
     popd 2>&1> /dev/null
}

info() {
     local green="\033[1;32m"
     local normal="\033[0m"
     echo -e "[${green}INFO${normal}] $1"
}

error() {
     local red="\033[1;31m"
     local normal="\033[0m"
     echo -e "[${red}ERROR${normal}] $1"
}

# 获取当前目录
current_dir() {
    if [ ${0:0:1} = '/' ] || [ ${0:0:1} = '~' ]; then
        echo "$(dirname $0)"
    else
        echo "`pwd`/$(dirname $0)"
    fi
}

usage() {
cat << EOF
`version`

USAGE: `basename $0` [-v|--version] [-h|--help] [-s|--enable-simulator] [-d|--enable-debug] [-p|--prefix <install directory>]

DESCRIPTION:
This command can generate makefile to build xcode project in command line just like <configure & make & make install> in C/C++ language world.

OPTION:
-v|--version                    show the version
-h|--help                       show the help
-s|--enable-simulator           enable simulator
-d|--enable-debug               enable debug
-p|--prefix PATH                assign the directory for install(default is ./target)

EOF
}

version() {
    echo "`basename $0` $VERSION by $AUTHOR"
}

check_command() {
    if [ -z `command -v $1` ];then
        error "checking for $1... no"
        return -1
    else
        info "checking for $1... yes"
    fi
}

# checking for environment
check_env() {
    check_command xcodebuild
    check_command make
    check_command mkdir
    check_command test
    check_command zip
    check_command rm
    check_command cp
    check_command awk
    check_command ls
    check_command pwd
    check_command sed
    check_command lipo
}

BUILD_CONFIGURATION=Release
ENABLE_SIMULATOR=0
WORKSPACES_COUNT=`ls|awk '/.xcworkspace/{print $0}'|awk 'BEGIN{t=0;} {t++;}  END{print t;}'`
PROJECTS_COUNT=`ls|awk '/.xcodeproj/{print $0}'|awk 'BEGIN{t=0;} {t++;}  END{print t;}'`
INSTALL_DIRECTORY=./target
BUILD_DIRECTORY=/tmp/xcodebuild/`pwd|xargs basename`
PHONY=

# select project

project_parse() {
    if [ $WORKSPACES_COUNT -gt 1 ];then
        index=0
        echo -e '\nPlease select a workspace to configure'
        i=0
        for item in `ls|awk '/.xcworkspace/{print "\""$0"\""}'|xargs basename |sed 's/ /__-__/g'`; do
            WORKSPACES[i]=`echo $item|sed 's/__-__/ /g'`
            echo [$i] - ${WORKSPACES[i]}
            i=$(($i+1))
        done
        echo -e 'Please choose an option [0] :\c' 
        read index

        if [ -z "$index" ];then
        index=0
        fi

        if [ -n "`echo $index | sed 's/[0-9]//g'`" ];then
            error "Invalid Option."
            exit
        fi

        if [ $index -ge $WORKSPACES_COUNT -o $index -lt 0 ];then
            error "Invalid Option."
            exit
        fi
        WORKSPACE=${WORKSPACES[$index]}
    elif [ $WORKSPACES_COUNT -lt 1 ];then
        index=0
        if [ $PROJECTS_COUNT -gt 1 ];then
            echo -e '\nPlease select a project to configure'
            i=0
            for item in `ls|awk '/.xcodeproj/{print "\""$0"\""}'|xargs basename|sed 's/ /__-__/g'`; do
                PROJECTS[i]=`echo $item|sed 's/__-__/ /g'`
                echo [$i] - ${PROJECTS[i]}
                i=$(($i+1))
            done
            echo -e 'Please choose an option [0] :\c' 
            read index

            if [ -z "$index" ];then
                index=0
            fi

            if [ -n "`echo $index | sed 's/[0-9]//g'`" ];then
                error "Invalid Option."
                exit
            fi

            if [ $index -ge $PROJECTS_COUNT -o $index -lt 0 ];then
                error "Invalid Option."
                exit
            fi
            PROJECT=${PROJECTS[$index]}
        elif [ $PROJECTS_COUNT -eq 1 ];then
            PROJECT=`ls|awk '/.xcodeproj/{print "\""$0"\""}'|xargs basename`
        else 
            error 'No xcode project'
            exit
        fi
    else
        WORKSPACE=`ls|awk '/.xcodeproj/{print "\""$0"\""}'|xargs basename`
    fi


    if [ -n "$PROJECT" ];then
        BUILD_PROJECT="-project \"$PROJECT\""
    fi

    if [ -n "$WORKSPACE" ];then
        BUILD_WORKSPACE="-workspace '$WORKSPACE'"
    fi
}


phony_add() {
    while [ -n "$1" ]
    do
        PHONY="$PHONY $1"        
        shift;
    done
}

param_parse() {
    while [ -n "$1" ]
    do
        case "$1" in
            -h|--help)
                usage;exit;;
            -v|--version)
                version;exit;;
            -d|--enable-debug)
                BUILD_CONFIGURATION=Debug;;
            -s|--enable-simulator)
                ENABLE_SIMULATOR=1;;
            -p|--prefix)
                INSTALL_DIRECTORY=$2;shift;;
            *)
                echo "Invalid $1";
                usage;exit;;
        esac
        shift;
    done
}

param_parse $*

# $1 - build configuration
# $2 - build directory
# $3 - install directory
# $4 - schemes
makefile_header() {
configuration=$1
build_directory=$2
install_directory=$3
schemes=$4

cat << EOF
generate_ipa=\\
    rm -rf "$build_directory/target/Payload"; \\
    mkdir -p "$build_directory/target/Payload"; \\
    cp -rf "$build_directory/Build/Products/$configuration-iphoneos/\$1.app" "$build_directory/target/Payload"; \\
    zip -r "$build_directory/target/\$1.ipa" "$build_directory/target/Payload"; \\
    rm -rf "$build_directory/target/Payload"

generate_lib=\\
    mkdir -p "$build_directory/target/\$1/include";\\
    cp -rf "$build_directory/Build/Products/$configuration-iphoneos/include/\$1" "$build_directory/target/\$1/include";\\
    cp -rf "$build_directory/Build/Products/$configuration-iphoneos/lib\$1.a" "$build_directory/target/\$1"; \\
    if [ $ENABLE_SIMULATOR -eq "1" ]; then \\
        lipo -create "$build_directory/Build/Products/$configuration-iphoneos/lib\$1.a" "$build_directory/Build/Products/$configuration-iphonesimulator/lib\$1.a" -output "$build_directory/target/\$1/lib\$1.a";\\
    fi

generate_framework=\\
    cp -rf "$build_directory/Build/Products/$configuration-iphoneos/\$1.framework" "$build_directory/target";\\
    if [ $ENABLE_SIMULATOR -eq "1" ]; then \\
        lipo -create "$build_directory/Build/Products/$configuration-iphoneos/\$1.framework/\$1" "$build_directory/Build/Products/$configuration-iphonesimulator/\$1.framework/\$1" -output "$build_directory/target/\$1.framework/\$1";\\
    fi

EOF

phony_add all

for scheme in $schemes; do
    scheme=`echo $scheme|sed 's/__-__/\\\\ /g'`
    original_schemes="$original_schemes $scheme"
    phony_add $scheme
    install_dependent="$install_dependent $scheme-install"
    clean_dependent="$clean_dependent $scheme-clean"
done

phony_add $install_dependent $clean_dependent

cat << EOF
all: $original_schemes

clean:$clean_dependent

install_prepare:
`printf "\t"`@mkdir -p "$install_directory"

install:install_prepare $install_dependent
EOF

phony_add install_prepare clean install
}

makefile_scheme() {
scheme=$1
configuration=$2
build_directory=$3
install_directory=$4

phony_add $1-device

cat << EOF

$1-device:
`printf "\t"`xcodebuild $BUILD_WORKSPACE $BUILD_PROJECT -configuration "$configuration" -scheme $1 -derivedDataPath "$build_directory" -sdk iphoneos
EOF

if [ $ENABLE_SIMULATOR -eq "1" ]; then
phony_add $1-simulator

cat << EOF
$1-simulator:
`printf "\t"`xcodebuild $BUILD_WORKSPACE $BUILD_PROJECT  -configuration "$configuration" -scheme $1 -derivedDataPath "$build_directory" -sdk iphonesimulator
$1:$1-device $1-simulator
EOF
else
cat << EOF
$1:$1-device
EOF
fi

cat << EOF
`printf "\t"`@mkdir -p "$build_directory/target"
`printf "\t"`@if test -d "$build_directory/Build/Products/$configuration-iphoneos/$scheme.app"; then \\
`printf "\t\t"`\$(call generate_ipa,$scheme); \\
`printf "\t"`fi

`printf "\t"`@if test -f "$build_directory/Build/Products/$configuration-iphoneos/lib$scheme.a"; then \\
`printf "\t\t"`\$(call generate_lib,$scheme); \\
`printf "\t"`fi

`printf "\t"`@if test -d "$build_directory/Build/Products/$configuration-iphoneos/$scheme.framework"; then \\
`printf "\t\t"`\$(call generate_framework,$scheme); \\
`printf "\t"`fi
EOF

# clean
cat << EOF
$1-clean:
`printf "\t"`xcodebuild clean $BUILD_WORKSPACE $BUILD_PROJECT -configuration "$configuration" -scheme $1 -derivedDataPath "$build_directory" -sdk iphoneos
EOF

if [ $ENABLE_SIMULATOR -eq "1" ]; then
cat << EOF
`printf "\t"`xcodebuild clean $BUILD_WORKSPACE $BUILD_PROJECT -configuration "$configuration" -scheme $1 -derivedDataPath "$build_directory" -sdk iphonesimulator
EOF
fi

# install
cat << EOF
$1-install:$1
`printf "\t"`@test ! -f "$build_directory/target/$scheme.ipa" || cp -rf "$build_directory/target/$scheme.ipa" "$install_directory"
`printf "\t"`@test ! -d "$build_directory/target/$scheme" || cp -rf "$build_directory/target/$scheme" "$install_directory"
`printf "\t"`@test ! -d "$build_directory/target/$scheme.framework" || cp -rf "$build_directory/target/$scheme.framework" "$install_directory"
`printf "\t"`@echo "Installed to $install_directory..."

EOF

}

makefile_footer() {
cat << EOF
.PHONY: $PHONY
EOF
}

project_parse

check_env

if [ -n "$WORKSPACE" ];then
    SCHEMES=`xcodebuild -workspace "$WORKSPACE" -list|sed -n '/Schemes/,/^$/p'|grep -v "Schemes:"|sed 's/^ *//'|sed 's/ /__-__/g'`
elif [ -n "$PROJECT" ];then
    SCHEMES=`xcodebuild -project "$PROJECT" -list|sed -n '/Schemes/,/^$/p'|grep -v "Schemes:"|sed 's/^ *//'|sed 's/ /__-__/g'`    
fi

info "build into $BUILD_DIRECTORY ..."
makefile_header "$BUILD_CONFIGURATION" "$BUILD_DIRECTORY" "$INSTALL_DIRECTORY" "$SCHEMES" > Makefile

for scheme in $SCHEMES; do
    makefile_scheme "`echo $scheme|sed 's/__-__/\\\\ /g'`" "$BUILD_CONFIGURATION" "$BUILD_DIRECTORY" "$INSTALL_DIRECTORY">> Makefile
done
makefile_footer >> Makefile

info 'generate makefile done. type make & make install'
